/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;

namespace Cobalt.Content.Pipeline.Quake.Bsp
{

	public class ImportedShaderContent : ContentItem
	{
		public ImportedShaderContent() { }

		public int SurfaceFlags { get; set; }
		public string ShaderText { get; set; }
		public int ContentFlags { get; set; }
	}

	public class ImportedCollisionBrushSide
	{
		public ImportedCollisionBrushSide()
		{
		}

		public Plane Plane { get; set; }
		public ImportedShaderContent Shader { get; set; }
	}

	public class ImportedCollisionBrushContent : ContentItem
	{
		public ImportedCollisionBrushContent()
		{
			Sides = new List<ImportedCollisionBrushSide>();
		}

		public List<ImportedCollisionBrushSide> Sides { get; private set; }
		public ImportedShaderContent Shader { get; set; }
	}

	public class ImportedNodeContent : ContentItem
	{
		public ImportedNodeContent()
		{
			Surfaces = new List<GeometryContent>();
			Brushes = new List<ImportedCollisionBrushContent>();
		}

		public bool IsLeaf { get; set; }

		/// <summary>
		/// Gets or sets the node's dividing plane.
		/// </summary>
		/// <remarks>
		/// This is only valid on interior nodes.
		/// </remarks>
		public Plane Plane { get; set; }

		/// <summary>
		/// Gets or sets this node's first child.
		/// </summary>
		/// <remarks>
		/// This is only valid on interior nodes.
		/// </remarks>
		public ImportedNodeContent Child0 { get; set; }

		/// <summary>
		/// Gets or sets this node's second child.
		/// </summary>
		/// <remarks>
		/// This is only valid on interior nodes.
		/// </remarks>
		public ImportedNodeContent Child1 { get; set; }

		/// <summary>
		/// Gets or sets this node's PVS cluster.
		/// </summary>
		/// <remarks>
		/// This is only valid on leaf nodes.
		/// </remarks>
		public PvsCluster Cluster { get; set; }

		/// <summary>
		/// Gets or sets this node's area number.
		/// </summary>
		/// <remarks>
		/// This is only valid on leaf nodes.
		/// </remarks>
		public int Area { get; set; }

		/// <summary>
		/// Gets the list of surfaces contained in this node.
		/// </summary>
		/// <remarks>
		/// This is only valid on leaf nodes.
		/// </remarks>
		public List<GeometryContent> Surfaces { get; private set; }

		/// <summary>
		/// Gets the list of collision brushes in this node.
		/// </summary>
		/// <remarks>
		/// This is only valid on leaf nodes.
		/// </remarks>
		public List<ImportedCollisionBrushContent> Brushes { get; private set; }

		/// <summary>
		/// Gets the node's bounding box.
		/// </summary>
		public BoundingBox BoundingBox { get; set; }
	}

	public class ImportedBrushModelContent : ContentItem
	{
		public ImportedBrushModelContent()
		{
			Surfaces = new List<GeometryContent>();
		}

		public List<GeometryContent> Surfaces { get; private set; }
	}

	public class ImportedMaterialContent : MaterialContent
	{
		public ImportedMaterialContent()
		{
		}

		public ImportedMaterialContent( ImportedShaderContent shader, Texture2DContent lightmap )
		{
			this.Shader = shader;
			this.Lightmap = lightmap;
		}

		public ImportedShaderContent Shader { get; set; }
		public Texture2DContent Lightmap { get; set; }

		public Shaders.Shader ParsedShader { get; set; }
	}

	public class PvsCluster
	{
		public int ClusterNum { get; set; }

		private Dictionary<PvsCluster, bool> visibility
			= new Dictionary<PvsCluster, bool>();

		public bool CanSee( PvsCluster other )
		{
			return visibility.ContainsKey( other );
		}

		public void AddLink( PvsCluster other )
		{
			if( other != this )
				visibility[other] = true;
		}

		public void BreakLink( PvsCluster other )
		{
			visibility.Remove( other );
		}

		public IEnumerable<PvsCluster> Links
		{
			get { return visibility.Keys; }
		}
	}

	public class PvsContent : ContentItem
	{
		public PvsContent()
		{
			Clusters = new List<PvsCluster>();
		}

		public List<PvsCluster> Clusters { get; private set; }
	}

	public static class EntityKeys
	{
		public const string ClassName = "classname";

		public const string Message = "message";
		public const string DeluxeMapping = "deluxemapping";

		public const string Origin = "origin";
		public const string Angle = "angle";

		public const string Light = "light";
		public const string Color = "_color";

		public const string Target = "target";
		public const string TargetName = "targetname";
	}

	public static class EntityClasses
	{
		public const string WorldSpawn = "worldspawn";
		public const string Light = "light";
	}

	public class ImportedEntityContent : ContentItem
	{
		public ImportedEntityContent()
		{
			Values = new Dictionary<string, string>();
		}

		public Dictionary<string, string> Values { get; private set; }

		public string ClassName
		{
			get
			{
				string ret;
				if( !Values.TryGetValue( EntityKeys.ClassName, out ret ) )
					return null;

				return ret;
			}
			set { Values[EntityKeys.ClassName] = value; }
		}
	}

	public class ImportedBspContent : ContentItem
	{
		public ImportedBspContent()
		{
			Entities = new List<ImportedEntityContent>();
			Mesh = new MeshContent();
			Leaves = new List<ImportedNodeContent>();
			Nodes = new List<ImportedNodeContent>();
			CollisionBrushes = new List<ImportedCollisionBrushContent>();
			BrushModels = new List<ImportedBrushModelContent>();
			Shaders = new List<ImportedShaderContent>();
			Materials = new List<ImportedMaterialContent>();
			Lightmaps = new List<Texture2DContent>();
			Deluxemaps = new List<Texture2DContent>();
		}

		public List<ImportedEntityContent> Entities { get; private set; }
		public MeshContent Mesh { get; private set; }
		public List<ImportedNodeContent> Leaves { get; private set; }
		public List<ImportedNodeContent> Nodes { get; private set; }
		public PvsContent PvsData { get; set; }
		public List<ImportedCollisionBrushContent> CollisionBrushes { get; private set; }
		public List<ImportedBrushModelContent> BrushModels { get; private set; }
		public List<ImportedShaderContent> Shaders { get; private set; }
		public List<ImportedMaterialContent> Materials { get; private set; }
		public List<Texture2DContent> Lightmaps { get; private set; }
		public bool RescaleLightmaps { get; set; }
		public List<Texture2DContent> Deluxemaps { get; private set; }
	}

}